#pragma once
#include<mutex>
#include<iostream>
#include<thread>
namespace wbx
{
	////释放用new申请的资源
	//template <class T>
	//struct DFdelete
	//{
	//	void operator()(T* ptr)
	//	{
	//		if (ptr)
	//		{
	//			delete ptr;
	//			ptr = nullptr;
	//		}
	//	}
	//};
	////释放用malloc申请的资源
	//template<class T>
	//struct DFfree
	//{
	//	void operator()(T* ptr)
	//	{
	//		if (ptr)
	//		{
	//			free(ptr);
	//			ptr = nullptr;
	//		}
	//	}
	//};
	////释放文件句柄
	//struct DFclose
	//{
	//	void operator()(FILE* fp)
	//	{
	//		if (fp)
	//		{
	//			fclose(fp);
	//			fp = nullptr;
	//		}
	//	}
	//};
	////释放用new[]申请的空间
	//template<class T>
	//struct DFarr
	//{
	//	void operator()(T *ptr)
	//	{
	//		if (ptr)
	//		{
	//			delete[] ptr;
	//			ptr = nullptr;
	//		}
	//	}
	//};
	template<class T, class DF=DFdelete<T>>
	class shared_ptr
	{
	public:
		shared_ptr(T* p=nullptr)
			:ptr(p)
			,pcount(nullptr)
			,pmutex(nullptr)
		{
			if (ptr)
			{
				pcount = new size_t(0);
				pmutex = new std::mutex;
				add_mutex();
			}
		}
		T& operator* ()
		{
			return *ptr;
		}
		T* operator->()
		{
			return ptr;
		}
		~shared_ptr()
		{
			if (ptr)
			{
				relese();
			}
		}
		//拷贝构造：每次赋值或拷贝构造都给资源++
		shared_ptr(const shared_ptr<T,DF>& sp)
			:ptr(sp.ptr),
			pcount(sp.pcount)
			,pmutex(sp.pmutex)
		{
			add_mutex();
		}

		shared_ptr<T, DF>& operator=(const shared_ptr<T,DF>& sp)
		{
			if (ptr != sp.ptr)
			{//防止用相同的资源进行赋值
				if (ptr)
				{
					relese();
				}
				ptr = sp.ptr;
				pcount = sp.pcount;
				pmutex = sp.pmutex;
				add_mutex();
			}
			return *this;
		}
		
	private:
		//释放内存给资源计数器--
		void relese()
		{
			pmutex->lock();
			if (pcount)
			{
				--(*pcount);
			}
			pmutex->unlock();
			if (ptr&&(*pcount) == 0)
			{//如果资源存在而且计数为0那么释放资源
				DF()(ptr);
				ptr = nullptr;
				delete pcount;
				delete pmutex;
				pcount = nullptr;
				pmutex = nullptr;
			}
		}
		void add_mutex()
		{
			if (ptr&&pcount)
			{
				pmutex->lock();
				++(*pcount);
				pmutex->unlock();
			}
		}
		size_t* pcount ;
		T* ptr;
		std::mutex *pmutex;
	};
};